namespace Plugins.Engine
{
    using System;
    using System.Diagnostics.CodeAnalysis;
    using System.Globalization;
    using Plugins.Core.Interfaces;
    using Plugins.Engine.Internal;
    using Plugins.Interfaces;
    using Plugins.Library;

    [Serializable]
    public class PluginHostManager : PluginCollectionContainer, IPluginHostManager, IPluginCollectionContainer, IPluginEnumerator
    {
        private IPluginObjectManager _objectManager;

        public PluginHostManager()
        {
            this._objectManager = new PluginObjectManager(this);
        }

        [SuppressMessage("Microsoft.Design", "CA1004")]
        private static void AddServices<T>(IPluginObjectManager manager, IPluginObjectInternal obj)
        {
            obj.ProcessService(delegate(Type type)
            {
                Type[] services = type.GetInterfaces();
                foreach (Type service in services)
                {
                    //LogHelper.Write(string.Format(CultureInfo.InvariantCulture, "registering type={0} service={1}", type.Name, TypeHelper.GetServiceName(service) ));
                    if (manager.RegisterObject(service, obj))
                    {
                        PluginLog.WriteAsync(string.Format(CultureInfo.InvariantCulture, "register type={0} service={1}", PluginTypeHelper.GetTypeName(type), PluginTypeHelper.GetTypeName(service)));
                    }
                }
            });
        }

        [SuppressMessage("Microsoft.Design", "CA1004")]
        private static IPluginConfiguration Load<T>(IPluginHostManager manager, Guid hostId, string hostName, string fileName, bool isDefault)
        {
            if (!string.IsNullOrEmpty(hostName))
            {
                string name = PluginTypeHelper.GetHostName(hostName, typeof(T));
                IPluginConfiguration host = manager.GetHost(name);
                if (host == null)
                {
                    host = new PluginConfiguration<T>(hostId, hostName, fileName, isDefault);
                    host.LoadConfiguration(manager, name);
                    LoadServices<T>(manager);
                }
                return host;
            }
            return null;
        }

        [SuppressMessage("Microsoft.Design", "CA1004")]
        public static IPluginConfiguration LoadHost<T>(IPluginHostManager manager, Guid hostId, string hostName, string fileName, bool isDefault)
        {
            if (manager != null)
            {
                return Load<T>(manager, hostId, hostName, fileName, isDefault);
            }
            return null;
        }

        [SuppressMessage("Microsoft.Design", "CA1004")]
        private static void LoadServices<T>(IPluginHostManager manager)
        {
            IPluginObjectCollection<T> plugins = PluginCollectionContainer.GetLoadedPlugins<T>(manager);
            if (plugins != null)
            {
                foreach (IPluginObjectInternal plugin in plugins)
                {
                    AddServices<T>(manager.ObjectManager, plugin);
                }
            }
        }

        [SuppressMessage("Microsoft.Design", "CA1031")]
        public static void ProcessActivePlugins(IPluginCollectionContainer host, PluginObjectAction action, Type type)
        {
            try
            {
                IPluginObjectCollection plugins = PluginCollectionContainer.GetActivePlugins(host, type);
                if (plugins != null)
                {
                    plugins.ProcessObject(action);
                }
            }
            catch (Exception ex)
            {
                PluginLog.WriteErrorSync(ex);
            }
        }

        [SuppressMessage("Microsoft.Design", "CA1031")]
        public static void ProcessLoadedPlugins(IPluginCollectionContainer host, PluginObjectAction action, Type type)
        {
            try
            {
                IPluginObjectCollection plugins = PluginCollectionContainer.GetLoadedPlugins(host, type);
                if (plugins != null)
                {
                    plugins.ProcessObject(action);
                }
            }
            catch (Exception ex)
            {
                PluginLog.WriteErrorSync(ex);
            }
        }

        [SuppressMessage("Microsoft.Design", "CA1004")]
        [SuppressMessage("Microsoft.Design", "CA1031")]
        public static void ProcessActivePlugins<T>(IPluginCollectionContainer host, Action<T> action) where T : class, IPluginServiceProvider<T>
        {
            try
            {
                IPluginObjectCollection<T> plugins = PluginCollectionContainer.GetActivePlugins<T>(host);
                if (plugins != null)
                {
                    plugins.ProcessObject(action);
                }
            }
            catch (Exception ex)
            {
                PluginLog.WriteErrorSync(ex);
            }
        }

        [SuppressMessage("Microsoft.Design", "CA1004")]
        [SuppressMessage("Microsoft.Design", "CA1031")]
        public static void ProcessLoadedPlugins<T>(IPluginCollectionContainer host, Action<T> action) where T : class, IPluginServiceProvider<T>
        {
            try
            {
                IPluginObjectCollection<T> plugins = PluginCollectionContainer.GetLoadedPlugins<T>(host);
                if (plugins != null)
                {
                    plugins.ProcessObject(action);
                }
            }
            catch (Exception ex)
            {
                PluginLog.WriteErrorSync(ex);
            }
        }

        [SuppressMessage("Microsoft.Design", "CA1004")]
        [SuppressMessage("Microsoft.Design", "CA1031")]
        public static void RegisterServiceProvider<T>(IPluginHostManager manager) where T : class, IPluginServiceProvider<T>
        {
            try
            {
                IPluginObjectCollection<T> plugins = PluginCollectionContainer.GetLoadedPlugins<T>(manager);
                if (plugins != null)
                {
                    plugins.ProcessObject(delegate(T plugin)
                    {
                        plugin.Initialize(manager.ObjectManager);
                        plugin.Register(manager.ObjectManager);
                    });
                }
            }
            catch (Exception ex)
            {
                PluginLog.WriteErrorSync(ex);
            }
        }

        [SuppressMessage("Microsoft.Design", "CA1004")]
        [SuppressMessage("Microsoft.Design", "CA1031")]
        public static void RegisterObject<T>(IPluginCollectionContainer manager, Action<T> action)
        {
            try
            {
                IPluginObjectCollection<T> plugins = PluginCollectionContainer.GetLoadedPlugins<T>(manager);
                if (plugins != null)
                {
                    plugins.ProcessObject(action);
                }
            }
            catch (Exception ex)
            {
                PluginLog.WriteErrorSync(ex);
            }
        }

        [SuppressMessage("Microsoft.Design", "CA1004")]
        private static void RemoveServices<T>(IPluginObjectManager manager, IPluginObjectInternal obj)
        {
            obj.ProcessService(delegate(Type type)
            {
                Type[] services = type.GetInterfaces();
                foreach (Type service in services)
                {
                    //LogHelper.Write(string.Format(CultureInfo.InvariantCulture, "unregistering type={0} service={1}", type.Name, TypeHelper.GetServiceName(service) ));
                    if (manager.UnregisterObject(service, obj))
                    {
                        PluginLog.WriteAsync(string.Format(CultureInfo.InvariantCulture, "unregister type={0} service={1}", PluginTypeHelper.GetTypeName(type), PluginTypeHelper.GetTypeName(service)));
                    }
                }
            });
        }

        [SuppressMessage("Microsoft.Design", "CA1004")]
        private static IPluginConfiguration Unload<T>(IPluginHostManager manager, string hostName)
        {
            if (!string.IsNullOrEmpty(hostName))
            {
                string name = PluginTypeHelper.GetHostName(hostName, typeof(T));
                IPluginConfiguration host = manager.GetHost(name);
                if (host != null)
                {
                    UnloadServices<T>(manager);
                    host.UnloadConfiguration(manager, name);
                }
                return host;
            }
            return null;
        }

        [SuppressMessage("Microsoft.Design", "CA1004")]
        public static IPluginConfiguration UnloadHost<T>(IPluginHostManager manager, IPluginConfigurationHost configuration)
        {
            if (manager != null && configuration != null)
            {
                return Unload<T>(manager, configuration.Host.Name);
            }
            return null;
        }

        [SuppressMessage("Microsoft.Design", "CA1004")]
        private static void UnloadServices<T>(IPluginHostManager manager)
        {
            IPluginObjectCollection<T> plugins = PluginCollectionContainer.GetLoadedPlugins<T>(manager);
            if (plugins != null)
            {
                foreach (IPluginObjectInternal plugin in plugins)
                {
                    RemoveServices<T>(manager.ObjectManager, plugin);
                }
            }
        }

        [SuppressMessage("Microsoft.Design", "CA1004")]
        [SuppressMessage("Microsoft.Design", "CA1031")]
        public static void UnregisterServiceProvider<T>(IPluginHostManager manager) where T : class, IPluginServiceProvider<T>
        {
            try
            {
                IPluginObjectCollection<T> plugins = PluginCollectionContainer.GetLoadedPlugins<T>(manager);
                if (plugins != null)
                {
                    plugins.ProcessObject(delegate(T plugin)
                    {
                        plugin.Unregister(manager.ObjectManager);
                        plugin.Finalize(manager.ObjectManager);
                    });
                }
            }
            catch (Exception ex)
            {
                PluginLog.WriteErrorSync(ex);
            }
        }

        [SuppressMessage("Microsoft.Design", "CA1004")]
        [SuppressMessage("Microsoft.Design", "CA1031")]
        public static void UnregisterObject<T>(IPluginCollectionContainer manager, Action<T> action)
        {
            try
            {
                IPluginObjectCollection<T> plugins = PluginCollectionContainer.GetLoadedPlugins<T>(manager);
                if (plugins != null)
                {
                    plugins.ProcessObject(action);
                }
            }
            catch (Exception ex)
            {
                PluginLog.WriteErrorSync(ex);
            }
        }

        public IPluginObjectManager ObjectManager
        {
            get
            {
                return this._objectManager;
            }
        }
    }
}

